package io.terminus.lego.shinda.web.security.special_user.provider

import io.terminus.lego.shinda.service.service.SpecialUserService
import io.terminus.lego.shinda.web.cache.RedisCacheManager
import io.terminus.lego.shinda.web.cache.RedisKeyConstant
import io.terminus.lego.shinda.web.security.phone.token.SpecialUserLoginAuthenticationToken
import io.terminus.lego.shinda.web.security.special_user.exception.SpecialUserAuthenticationException
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.core.Authentication
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Component

/**
 * 特殊用户认证服务提供者
 * @author wangmeng
 * @date 2018/4/28
 */
@Component
class SpecialUserAuthenticationProvider @Autowired constructor(val specialUserService: SpecialUserService,
                                                               val redisCacheManager: RedisCacheManager,
                                                               val passwordEncoder: PasswordEncoder) : AuthenticationProvider {
    private val retryLimit = 5

    override fun authenticate(authentication: Authentication): Authentication {
        authentication as SpecialUserLoginAuthenticationToken
        //关键信息
        val specialUsername = authentication.principal.toString()
        val userType = authentication.getUserType()
        val password = authentication.credentials.toString()
        val specialUserLoginRetryKey = RedisKeyConstant.getSpecialUserLoginRetryKey(specialUsername)
        val specialUserLoginSmsKey = RedisKeyConstant.getSpecialUserLoginCodelKey(specialUsername)

        val user = specialUserService.findUserByUsernameAndType(specialUsername, userType)
                ?: throw SpecialUserAuthenticationException("user.not.exist")
        //检查错误次数
        val retry = ((redisCacheManager.getValue(specialUserLoginRetryKey) ?: 0) as Int)
        if (retry >= retryLimit) {
            throw SpecialUserAuthenticationException("user.was.locked.retry.5.mints.later")
        }
        //校验密码
        if (passwordEncoder.matches(password, user.password)) {
            //user.username将成为为authentication.name
            val authenticationResult = SpecialUserLoginAuthenticationToken(user.username!!, "", emptyList(), userType)
            authenticationResult.details = user
            redisCacheManager.remove(specialUserLoginRetryKey)
            redisCacheManager.remove(specialUserLoginSmsKey)
            return authenticationResult
        }
        //增加错误次数
        redisCacheManager.setValue(specialUserLoginRetryKey, retry + 1)
        throw SpecialUserAuthenticationException("password.mismatch")
    }

    override fun supports(authentication: Class<*>?): Boolean {
        return authentication == SpecialUserLoginAuthenticationToken::class.java
    }


}